#pragma once

// 引入必要的头文件
#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include "Comm.hpp" // 自定义通信相关头文件

// 默认共享内存标识符和大小
const int gdefaultid = -1;        // 默认无效共享内存ID
const int gsize = 4096;           // 默认共享内存大小（4KB）
const std::string pathname = "."; // 生成System V IPC key的路径
const int projid = 0x66;          // 生成System V IPC key的项目ID
const int gmode = 0666;           // 共享内存权限（rw-rw-rw-）

// 用户类型标识
#define CREATER "creater" // 创建者（负责创建和销毁共享内存）
#define USER "user"       // 普通用户（仅连接现有共享内存）

/**
 * @class Shm
 * @brief 封装System V共享内存操作的C++类
 *
 * 提供共享内存的创建、连接、状态查询、销毁等完整生命周期管理功能
 * 通过用户类型区分创建者/使用者，实现自动化资源管理（RAII）
 */
class Shm
{
private:
    /**
     * @brief 辅助函数：创建/获取共享内存
     * @param flg shmget的标志参数（如IPC_CREAT等）
     *
     * 注意：共享内存的生命周期由内核管理，需显式删除
     */
    void CreateHelper(int flg)
    {
        printf("生成System V IPC key: 0x%x\n", _key);
        _shmid = shmget(_key, _size, flg); // 调用shmget获取共享内存ID
        if (_shmid < 0)
        {
            ERR_EXIT("shmget失败"); // 错误处理
        }
        printf("获取共享内存ID: %d\n", _shmid);
    }

    /**
     * @brief 创建全新的共享内存（需确保不存在）
     */
    void Create()
    {
        // 使用排他创建模式（IPC_CREAT | IPC_EXCL）
        CreateHelper(IPC_CREAT | IPC_EXCL | gmode);
    }

    /**
     * @brief 将共享内存附加到当前进程地址空间
     */
    void Attach()
    {
        _start_mem = shmat(_shmid, nullptr, 0); // 连接共享内存
        if ((long long)_start_mem < 0)          // 检查返回值（Linux返回(void*)-1）
        {
            ERR_EXIT("shmat失败");
        }
        printf("共享内存连接成功\n");
    }

    /**
     * @brief 断开共享内存连接
     */
    void Detach()
    {
        int n = shmdt(_start_mem); // 断开共享内存连接
        if (n == 0)
        {
            printf("共享内存断开成功\n");
        }
    }

    /**
     * @brief 获取已存在的共享内存
     */
    void Get()
    {
        CreateHelper(IPC_CREAT); // 仅使用创建标志（不排他）
    }

    /**
     * @brief 销毁共享内存资源
     *
     * 1. 先断开当前进程的连接
     * 2. 如果是创建者则删除共享内存
     */
    void Destroy()
    {
        Detach(); // 无论用户类型都需要断开连接

        if (_usertype == CREATER)
        {
            // 设置IPC_RMID标志，标记共享内存为待删除
            int n = shmctl(_shmid, IPC_RMID, nullptr);
            if (n >= 0)
            {
                printf("成功删除共享内存: %d\n", _shmid);
            }
            else
            {
                ERR_EXIT("shmctl失败");
            }
        }
    }

public:
    /**
     * @brief 构造函数
     * @param pathname 生成key的路径
     * @param projid 生成key的项目ID
     * @param usertype 用户类型（CREATER/USER）
     *
     * 构造流程：
     * 1. 生成IPC key
     * 2. 根据用户类型创建/获取共享内存
     * 3. 自动连接共享内存
     */
    Shm(const std::string &pathname, int projid, const std::string &usertype)
        : _shmid(gdefaultid),  // 初始化共享内存ID为无效值
          _size(gsize),        // 设置默认大小
          _start_mem(nullptr), // 初始化内存地址指针
          _usertype(usertype)  // 记录用户类型
    {
        // 生成System V IPC key
        _key = ftok(pathname.c_str(), projid);
        if (_key < 0)
        {
            ERR_EXIT("ftok失败");
        }

        // 根据用户类型选择操作
        if (_usertype == CREATER)
            Create(); // 创建者：创建新共享内存
        else if (_usertype == USER)
            Get(); // 使用者：获取现有共享内存

        Attach(); // 无论创建者还是使用者都需要连接内存
    }

    /**
     * @brief 获取共享内存的虚拟地址
     * @return 共享内存起始地址
     */
    void *VirtualAddr()
    {
        printf("返回虚拟地址: %p\n", _start_mem);
        return _start_mem;
    }

    /**
     * @brief 获取共享内存大小
     * @return 共享内存字节数
     */
    int Size()
    {
        return _size;
    }

    /**
     * @brief 打印共享内存属性
     *
     * 显示信息包括：
     * - 共享内存段大小
     * - 关联的IPC key值
     */
    void Attr()
    {
        struct shmid_ds ds;
        // 获取共享内存状态信息
        int n = shmctl(_shmid, IPC_STAT, &ds);
        printf("共享内存段大小: %ld 字节\n", ds.shm_segsz);
        printf("关联IPC key: 0x%x\n", ds.shm_perm.__key);
    }

    /**
     * @brief 析构函数
     *
     * 自动执行资源清理：
     * - 创建者：删除共享内存
     * - 所有用户：断开内存连接
     */
    ~Shm()
    {
        std::cout << "清理资源，用户类型: " << _usertype << std::endl;
        Destroy(); // 统一调用销毁方法处理清理逻辑
    }

private:
    int _shmid;            // 共享内存标识符
    key_t _key;            // System V IPC key
    int _size;             // 共享内存大小（字节）
    void *_start_mem;      // 共享内存起始地址指针
    std::string _usertype; // 用户类型标识（CREATER/USER）
};